home *** CD-ROM | disk | FTP | other *** search
/ MacHack 2001 / MacHack 2001.toast / pc / The Hacks / King of Swing / MusicClasses.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-06-23  |  9.1 KB  |  407 lines

  1. #include "MusicClasses.h"
  2. #include <iostream.h>
  3.  
  4. void GenerateHexFromLong(long initial, ofstream& outFile);
  5.  
  6. Note Measure::getStackedNote(int n){ 
  7.     Note retNote;
  8.     if (numNotes < n) {
  9.         retNote.pitch = -100;
  10.         retNote.duration = 1;
  11.         retNote.volume = 0x40;
  12.     } else
  13.         retNote = noteLine[numNotes - n];
  14.         
  15.     return retNote;        
  16. }
  17.  
  18. void Song::OutputToFile(ofstream& outFile) {
  19.  
  20.     outFile << "MThd";            //header information
  21.     outFile.put(0x00);
  22.     outFile.put(0x00);
  23.     outFile.put(0x00);
  24.     outFile.put(0x06);
  25.     
  26.     outFile.put(0x00);
  27.     outFile.put(0x01);
  28.     outFile.put(0x00);
  29.     outFile.put(0x01);
  30.     outFile.put(0x00);
  31.     outFile.put(0x04);
  32.     
  33.     
  34.     outFile << "MTrk";            //track information
  35.     
  36.     long initial = CountNumBytes() + 4;
  37.     GenerateHexFromLong(initial, outFile); //length
  38.  
  39.     Unit* current = headPointer;
  40.     while (current != nil) {
  41.         current -> OutputToFile(outFile);
  42.         current = current -> getNext();
  43.     }
  44.     
  45.     outFile.put(0x00);
  46.     outFile.put(0xFF);
  47.     outFile.put(0x2F);
  48.     outFile.put(0x00);    
  49.         
  50. }
  51.  
  52. void Unit::OutputToFile(ofstream& outFile) {
  53.     for (int i = 0; i < 12; i++)
  54.         (mArray[i]).OutputToFile(outFile, i);
  55. }
  56.  
  57. void Measure::OutputToFile(ofstream& outFile, int measureNum) {
  58.     char chord[3];
  59.     
  60.     switch (measureNum) {
  61.         case 8:
  62.             chord[1] = 0x34;
  63.             chord[2] = 0x3A;
  64.             chord[3] = 0x3E;
  65.             break;
  66.         case 1: case 4: case 5: case 9:
  67.             chord[1] = 0x32;
  68.             chord[2] = 0x38;
  69.             chord[3] = 0x3C;
  70.             break;
  71.         case 3:
  72.             chord[1] = 0x33;
  73.             chord[2] = 0x39;
  74.             chord[3] = 0x3D;
  75.             break;
  76.         case 11:
  77.             chord[1] = 0x34;
  78.             chord[2] = 0x3A;
  79.             chord[3] = 0x3F;
  80.             break;    
  81.         default:
  82.             chord[1] = 0x33;
  83.             chord[2] = 0x39;
  84.             chord[3] = 0x3E;
  85.             break;
  86.     }            
  87.     
  88.     
  89.     for (int i = 0; i < 3; i++) {
  90.         outFile.put(0x00);                        //delta time is nothing
  91.         outFile.put(0x90);                        //note on event--channel 0 (i.e. 1)
  92.         outFile.put(chord[i]);                    //pitch plus F below middle C (in half steps)
  93.         outFile.put(0x40);                        //normal accent
  94.     }
  95.     
  96.     for (int i = 0; i < numNotes; i++)
  97.         noteLine[i].OutputToFile(outFile);
  98.     
  99. /*    outFile.put(0x00);            //stop! event
  100.     outFile.put(0xF7);
  101.     outFile.put(0x01);
  102.     outFile.put(0xFC);
  103.     
  104.     outFile.put(0x10);            //continue! event
  105.     outFile.put(0xF7);
  106.     outFile.put(0x01);
  107.     outFile.put(0xFB);    
  108. */    
  109.     for (int i = 0; i < 3; i++) {
  110.         outFile.put(0x00);                        //duration of note in ticks (16ths for now)
  111.         outFile.put(0x80);                        //note off event--channel 0 (i.e. 1)
  112.         outFile.put(chord[i]);                    //pitch plus F below middle C (in half steps) minus octove
  113.         outFile.put(0x40);                        //normal accent
  114.     }
  115.  
  116.  
  117. }
  118.  
  119. void Note::OutputToFile(ofstream& outFile) {
  120.     if (pitch == -100) {                //-100 means rest
  121.         outFile.put(0x00);            //stop event
  122.         outFile.put(0xF7);
  123.         outFile.put(0x01);
  124.         outFile.put(0xFC);
  125.         
  126.         outFile.put(char(duration));            //continue event
  127.         outFile.put(0xF7);
  128.         outFile.put(0x01);
  129.         outFile.put(0xFB);    
  130.     }
  131.     else {                                //otherwise send note on event
  132.         outFile.put(0x00);                        //delta time is nothing
  133.         outFile.put(0x90);                        //note on event--channel 0 (i.e. 1)
  134.         outFile.put((char)(0x35 + pitch));        //pitch plus F below middle C (in half steps)
  135.         outFile.put(volume);                        //normal accent
  136.         
  137.         outFile.put(char(duration));            //duration of note in ticks (16ths for now)
  138.         outFile.put(0x80);                        //note off event--channel 0 (i.e. 1)
  139.         outFile.put((char)(0x35 + pitch));        //pitch plus F below middle C (in half steps) minus octove
  140.         outFile.put(volume);                        //normal accent
  141.     }    
  142. }            
  143.  
  144. Song::Song()
  145. {
  146.     headPointer = new Unit;
  147. }
  148.  
  149. Song::Song(ifstream& fin)
  150. {    
  151.     Unit* curUnit;
  152.     headPointer = new Unit(fin);
  153.     headPointer->getNext() = new Unit(fin);
  154.     curUnit = headPointer->getNext();
  155.     curUnit->getNext() = new Unit(fin);
  156.     curUnit = curUnit->getNext();
  157.     curUnit->getNext() = new Unit(fin);
  158.     curUnit = curUnit->getNext();
  159.     curUnit->getNext() = new Unit(fin);
  160.     curUnit = curUnit->getNext();
  161.     curUnit->getNext() = new Unit(fin);
  162.     curUnit = curUnit->getNext();
  163. }
  164.  
  165. Unit::Unit(ifstream& fin) {
  166.     nextUnit = nil;
  167.  
  168.     PitchLine* p1;
  169.     SyncLine*  s1;
  170.     
  171.     pList = nil;
  172.     sList = nil;
  173.     
  174.     pList = new PitchLine(nil, fin);
  175.     sList = new SyncLine(nil, pList, fin);
  176.     
  177.     p1 = pList;
  178.     s1 = sList;
  179.     
  180.     for(short C = 1; C < 3; C++) {
  181.         p1->getNext() = new PitchLine(nil, fin);
  182.         s1->getNext() = new SyncLine(nil, pList, fin);
  183.         p1 = p1->getNext();                //increment p1
  184.         s1 = s1->getNext();
  185.     }
  186.     
  187.     WriteMeasures(fin);
  188. }
  189.  
  190.  
  191. long Song::CountNumBytes() {
  192.     Unit* curUnit = headPointer;
  193.     long numBytes = 0;
  194.     
  195.     for(numBytes = 0; curUnit != nil; curUnit = curUnit->getNext())
  196.         numBytes += curUnit->CountNumBytes();
  197.         
  198.     return numBytes;
  199.     
  200. }
  201.  
  202. long Unit::CountNumBytes() {
  203.     short measure;
  204.     long numBytes = 0;
  205.     
  206.     for (measure = 0; measure < 12; ++measure)
  207.         numBytes += 8*mArray[measure].GetNumNotes();
  208.     
  209.     numBytes += 12 * 24;    //chord bytes
  210.     return numBytes;    
  211. }
  212.  
  213. int Measure::GetNumNotes() {
  214.     return numNotes;
  215. }
  216.  
  217. void GenerateHexFromLong(long initial, ofstream& outFile) {
  218.     char zeroChar = 0x00;
  219.     char holder[4];
  220.  
  221.     for (int i = 0; i < 4; i++) {
  222.         holder[i] = initial | zeroChar;
  223.         initial >>= 8;
  224.     }
  225.     
  226.     for (int i = 0; i < 4; i++)
  227.         outFile.put(holder[3 - i]);
  228. }        
  229.  
  230. Note::Note(short newPitch, long newDuration)
  231.  :    pitch(newPitch),
  232.      duration(newDuration)
  233. {
  234. }
  235.     
  236.  
  237. int Measure::AddNote(Note newNote) {        //adds new note at end of part of measure written so far
  238.     noteLine[numNotes] = newNote;
  239.     return ++numNotes;            //prefix!!!
  240. }
  241.  
  242. void Unit::WriteMeasures(ifstream& fin) {
  243.     PitchLine*    plTemp;
  244.     SyncLine*    slTemp;
  245.     int beatCount;                    //16th note equivalents used so far this measure
  246.     int measureCount = 0;
  247.     int measureCountInPitchLine = 0;
  248.     char random;
  249.     Note     keyNote;
  250.     
  251.     plTemp = pList;
  252.     slTemp = sList;
  253.  
  254.     while (plTemp != nil && slTemp != nil) {
  255.         //pitch line loop:
  256.         for (measureCountInPitchLine = 0; measureCountInPitchLine < 4; measureCountInPitchLine++) {
  257.             //measure loop:
  258.             for (beatCount = 0; beatCount < 16; /*++beatCount*/) {
  259.                 fin >> random;
  260.                 keyNote = PickNote(measureCount, plTemp, slTemp, beatCount, random);
  261.                 mArray[measureCount].AddNote(keyNote);
  262.                 beatCount += keyNote.duration;
  263.             }
  264.             ++measureCount;    
  265.         }
  266.         plTemp = plTemp->getNext();
  267.         slTemp = slTemp->getNext();
  268.     }    
  269.  
  270. }
  271.  
  272. long min(long a, long b) {
  273.     return (a < b) ? a : b;
  274. }
  275.  
  276.  
  277. //Interesting functions begin here 
  278.  
  279.  
  280. PitchLine::PitchLine(PitchLine* pitchLineNext, ifstream& fin) {
  281.     next = pitchLineNext;
  282.     for (int i = 0; i < 16; i++)                    //good pitch line
  283.         pitchFunc[i] = (int) i;
  284.     for (int i = 16; i < 32; i++)
  285.         pitchFunc[i] = (int) ((i-16));
  286.     for (int i = 32; i < 48; i++)
  287.         pitchFunc[i] = (int) ((i-32));
  288.     for (int i = 48; i < 56; i++)
  289.         pitchFunc[i] = (int) ((i-32));
  290.     for (int i = 56; i < 64; i++)
  291.         pitchFunc[i] = (int) (80-i);
  292. }
  293.  
  294. SyncLine::SyncLine(SyncLine* syncLineNext, PitchLine* corrLine, ifstream& fin) {
  295. #pragma unused (corrLine)
  296.     next = syncLineNext;
  297.     for(short i = 0; i < 24; ++i)
  298.         syncFunc[i] = 1;            //all quarter notes
  299.     for(short i = 24; i < 38; ++i)
  300.         syncFunc[i] = 3;    
  301.     for(short i = 38; i < 54; ++i)
  302.         syncFunc[i] = 2;            //all dotted eighth notes    
  303.     for(short i = 54; i < 64; ++i)
  304.         syncFunc[i] = 1;    
  305. }
  306.  
  307. Note Unit::PickNote(int measureCount, PitchLine* pl, SyncLine* sl, int beatCount, char random) {
  308. #pragma unused(random)
  309.     Note endNote;
  310.     short linePitch;
  311.     int measureOfPL = measureCount % 4;
  312.     short rand = (short) random;
  313.     endNote.volume = 0x40;
  314.     
  315.     linePitch = pl->getPitch(measureOfPL*16 + beatCount);
  316.     if (rand > 136) linePitch += 3;
  317.     if (rand < 64) linePitch -= 3;
  318.     if (measureCount != 8) {
  319.         switch (linePitch % 12) {
  320.         case 1:
  321.             endNote.pitch = linePitch - 1;
  322.             break;
  323.         case 2:
  324.             endNote.pitch = linePitch + 1;
  325.             break;
  326.         case 4:
  327.             if (rand < 60)
  328.                 endNote.pitch = linePitch - 1;
  329.             else if (rand < 100)
  330.                 endNote.pitch = linePitch + 2;
  331.             else
  332.                 endNote.pitch = linePitch + 1;
  333.             break;
  334.         case 8:
  335.             endNote.pitch = linePitch - 1;
  336.             break;
  337.         case 9:
  338.             endNote.pitch = linePitch + 1;
  339.             break;
  340.         case 11:
  341.             if (rand < 72)
  342.                 endNote.pitch = linePitch - 1;
  343.             else
  344.                 endNote.pitch = linePitch + 1;
  345.             break;
  346.         default:
  347.     //    case 0: case 3: case 5: case 6: case 7: case 9:
  348.             endNote.pitch = linePitch;
  349.             break;
  350.         }
  351.     }
  352.     else {
  353.         switch (linePitch % 12) {
  354.         case 0:
  355.             endNote.pitch = linePitch - 1;
  356.             break;
  357.         case 1:
  358.             endNote.pitch = linePitch + 1;
  359.             break;
  360.         case 3:
  361.             endNote.pitch = linePitch - 1;
  362.             break;
  363.         case 4:
  364.             endNote.pitch = linePitch + 1;
  365.             break;
  366.         case 6:
  367.             endNote.pitch = linePitch + 1;
  368.             break;
  369.         case 8:
  370.             endNote.pitch = linePitch - 1;
  371.             break;
  372.         case 10:
  373.             endNote.pitch = linePitch - 1;
  374.             break;
  375.         default:
  376.     //    case 2: case 5: case 7: case 9: case 11:
  377.             endNote.pitch = linePitch;
  378.             break;
  379.         }
  380.     }
  381.     
  382.     char holder;
  383.     
  384.     if (endNote.pitch == mArray[measureCount].getStackedNote(1).pitch)
  385.         endNote.pitch = -100;        //don't repeat notes
  386.         
  387.     if (mArray[measureCount].getStackedNote(1).duration == 1 && mArray[measureCount].getStackedNote(2).duration == 1 && rand > 65) {
  388.         endNote.duration = 1;            //continuity of 16ths
  389.         holder = mArray[measureCount].getStackedNote(1).volume;
  390.         holder += 1;
  391.         mArray[measureCount].setStackedNoteV(1,holder);
  392.         endNote.volume = holder;
  393.     } else if (mArray[measureCount].getStackedNote(1).duration == 3) {
  394.         endNote.duration = 1;
  395.         mArray[measureCount].setStackedNoteV(1, 0x4E);
  396.     } else 
  397.         endNote.duration = min(sl->getSync(measureOfPL*16 + beatCount), 16 - beatCount);
  398.  
  399.     if ((endNote.duration >= 12-beatCount) && (rand % 3 == 0))
  400.         endNote.pitch = -100;
  401.         
  402.     if (measureCount == 11)
  403.         endNote.pitch = -100;
  404.         
  405.  
  406.     return endNote;
  407. }